package cn.tedu._07springaop.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Arrays;

/**
 * Aspect注解:表示这个类是一个切面类
 * 前置通知
 *
 * @Before 注解：前置通知：在目标方法执行之前执行
 */
@Aspect
@Component
public class LogAspect {
    @Before(value = "execution(public int cn.tedu._07springaop.aop.CalculatorImpl.*(..))")
    public void before(JoinPoint joinPoint) {
        /**
         *    getSignature(): 获取连接点签名信息;
         *    getName(): 获取连接点名称;
         *    getArgs(): 获取连接点参数;
         */
        String name = joinPoint.getSignature().getName();
        String strings = Arrays.toString(joinPoint.getArgs());
        System.out.println("[前置通知]" + name + "方法开始，参数为" + strings);
    }

    /**
     * After 注解：在被代理的目标方法最终结束后执行
     * 后置通知
     *
     * @param joinPoint
     */
    @After(value = "execution(public int cn.tedu._07springaop.aop.CalculatorImpl.*(..))")
    public void after(JoinPoint joinPoint) {
        String name = joinPoint.getSignature().getName();
        String strings = Arrays.toString(joinPoint.getArgs());
        System.out.println("[后置通知]" + name + "方法结束，参数为" + strings);
    }

    /**
     * AfterReturning 注解：在被代理的目标方法成功结束后执行
     * 返回通知
     */
    @AfterReturning(value = "execution(public int cn.tedu._07springaop.aop.CalculatorImpl.*(..))", returning = "result")
    public void afterReturning(JoinPoint joinPoint, Object result) {
        String name = joinPoint.getSignature().getName();
        System.out.println("[返回通知]" + name + "方法正常结束，返回值为" + result);
    }

    /**
     * AfterThrowing 注解：在被代理的目标方法异常结束后执行
     * 异常通知
     */
    @AfterThrowing(value = "execution(public int cn.tedu._07springaop.aop.CalculatorImpl.*(..))", throwing = "ex")
    public void AfterThrowing(JoinPoint joinPoint, Throwable ex) {
        String name = joinPoint.getSignature().getName();
        System.out.println("[异常通知]" + name + "方法抛出异常，异常信息为：" + ex.getMessage());
    }

    /**
     * Around 注解：环绕通知：在被代理的目标方法前后都执行
     * 环绕通知
     */
    @Around(value = "execution(public int cn.tedu._07springaop.aop.CalculatorImpl.*(..))")
    public Object around(ProceedingJoinPoint joinPoint) {
        Object result = null;
        try {
            //1.前置通知
            System.out.println("[环绕通知]：前置通知");

            //2.目标方法执行
            result = joinPoint.proceed();

            //3.返回通知
            System.out.println("[环绕通知]：返回通知");

        } catch (Throwable e) {
            System.out.println("[环绕通知]：异常通知");
            throw new RuntimeException(e);

        } finally {
            //5.后置通知
            System.out.println("[环绕通知]：后置通知");
        }
        return result;
    }

}
